home *** CD-ROM | disk | FTP | other *** search
- /*
- * Copyrighted as an unpublished work.
- * (c) Copyright 1991 Brian Smith
- * All rights reserved.
- *
- * Read the LICENSE file for details on distribution and use.
- *
- */
-
- #include <stdio.h>
- #include <fcntl.h>
- #include <dos.h>
- #include <alloc.h>
- #include <io.h>
- #include <string.h>
-
- #include "sb.h"
-
- #define TRUE 1
- #define FALSE 0
-
- #define lobyte(X) (((unsigned char *)&X)[0])
- #define hibyte(X) (((unsigned char *)&X)[1])
-
- /* Globals */
- int fm_herz; /* clock ticks per second */
- int tempo; /* clock ticks per quarter note */
- int fm_fd;
- int note_on[22];
- char **instrument_table;
- int note_table[12] = {
- 343,
- 363,
- 385,
- 408,
- 432,
- 458,
- 485,
- 514,
- 544,
- 577,
- 611,
- 647
- };
-
-
- int main(argc, argv)
- int argc;
- char **argv;
- {
- int cmf_fd;
-
- if (argc != 2)
- {
- printf("usage: %s <cmf file>\n", argv[0]);
- exit(-1);
- }
-
- /* open cmf file */
- cmf_fd = open(argv[1], O_RDONLY);
- if (cmf_fd == -1)
- {
- printf("usage: %s <cmf file>\n", argv[0]);
- exit(-1);
- }
-
- /* verify that file is a cmf file */
- if (!verify_cmf(cmf_fd))
- {
- printf("file was not a cmf file\n");
- printf("usage: %s <cmf file>\n", argv[0]);
- exit(-1);
- }
-
- /* read and set instruments from cmf file */
- get_instruments(cmf_fd);
-
- /* get timing */
- set_timing(cmf_fd);
-
- /* open soundblaster fm chips */
- Sb_FM_Reset();
-
- /* play song */
- play_song(cmf_fd);
-
- return(0);
- }
-
-
- /* check for "CTMF" in first four bytes of file */
- int verify_cmf(fd)
- int fd;
- {
- char idbuf[5];
-
- /* get id */
- lseek(fd, 0, SEEK_SET);
- if (read(fd, idbuf, 4) != 4)
- return(FALSE);
-
- /* compare to standard id */
- idbuf[4] = (char)0;
- if (strcmp(idbuf, "CTMF") != 0)
- return(FALSE);
-
- return(TRUE);
- }
-
- int get_instruments(fd)
- int fd;
- {
- int offset;
- int num_instruments;
- int i;
- int rc;
- int fnum, block, note;
- unsigned char tmp_byte;
-
- /* get offset of instrument block */
- offset = 0;
- lseek(fd, 0x06, SEEK_SET);
- read(fd, &tmp_byte, 1);
- lobyte(offset) = tmp_byte;
- read(fd, &tmp_byte, 1);
- hibyte(offset) = tmp_byte;
-
- /* get number of instruments */
- num_instruments = 0;
- lseek(fd, 0x24, SEEK_SET);
- read(fd, &tmp_byte, 1);
- lobyte(num_instruments) = tmp_byte;
- read(fd, &tmp_byte, 1);
- hibyte(num_instruments) = tmp_byte;
-
- /* allocate space */
- instrument_table = (char **)malloc(sizeof(int *) * num_instruments);
-
- /* read each instrument */
- lseek(fd, (long)offset, SEEK_SET);
- for (i=0; i< num_instruments; i++)
- {
- /* allocate space */
- instrument_table[i] = (char *)malloc(16);
-
- /* set instrument characteristics */
- read(fd, instrument_table[i], 16);
- }
-
- return(0);
- }
-
-
- /*
- * get and set timing parameters
- */
- int set_timing(fd)
- int fd;
- {
- unsigned char tmp_byte;
-
- /* get tempo */
- tempo = 0;
- lseek(fd, 0x0C, SEEK_SET);
- read(fd, &tmp_byte, 1);
- tempo = (unsigned int)tmp_byte;
- read(fd, &tmp_byte, 1);
- tempo += (unsigned int)tmp_byte << 8;
-
- /* get herz of timing clock */
- fm_herz = 0;
- lseek(fd, 0x0C, SEEK_SET);
- read(fd, &tmp_byte, 1);
- fm_herz = (unsigned int)tmp_byte;
- read(fd, &tmp_byte, 1);
- fm_herz += (unsigned int)tmp_byte << 8;
-
- return(0);
- }
-
-
- /*
- * seek to the midi stream and handle midi events for the song
- */
- int play_song(fd)
- int fd;
- {
- int offset;
- unsigned char tmp_byte;
- int delta;
-
- /* get offset of music stream */
- lseek(fd, 8, SEEK_SET);
- read(fd, &tmp_byte, 1);
- offset = (unsigned int)tmp_byte;
- read(fd, &tmp_byte, 1);
- offset += (unsigned int)tmp_byte << 8;
- lseek(fd, offset, SEEK_SET);
-
- /* process till EOF */
- while(1)
- {
- /* get delta time */
- delta = ReadVarLen(fd);
- if (delta == -1)
- break;
-
- /* wait delta */
- if (delta > 0)
- delay((double)delta/(double)fm_herz * 1000);
-
- /* process midi event */
- process_event(fd, delta);
- }
-
-
- return(0);
- }
-
-
- /*
- * read a variable length scalar in MIDI format
- */
- int ReadVarLen(fd)
- int fd;
- {
- int value;
- unsigned char tmp_byte;
-
- if (read(fd, &tmp_byte, 1) == 0)
- return(-1);
- value = (int)tmp_byte;
- if (tmp_byte & 0x80)
- {
- value &= 0x7F;
- do
- {
- if (read(fd, &tmp_byte, 1) == 0)
- return(-1);
- value = (value << 7) + (tmp_byte & 0x7F);
- } while (tmp_byte & 0x80);
- }
-
- return(value);
- }
-
-
- /*
- * process a midi event
- */
- int process_event(fd, delta)
- int fd;
- {
- int rc, channel;
- unsigned char tmp_byte;
- static int status = -1;
-
- /* get status byte */
- read(fd, &tmp_byte, 1);
- if (tmp_byte & 0x80)
- {
- status = (unsigned int)tmp_byte;
- }
- else
- {
- /* running status, so back up one */
- if (status == -1)
- {
- printf("ERROR in cmf file. Running status at beginning of file\n");
- exit(-1);
- }
- lseek(fd, -1, SEEK_CUR);
- }
-
- /* switch different events */
- switch (status & 0xF0)
- {
- case 0x80:
- /* turn note off */
- channel = status & 0x0f;
- Sb_FM_Key_Off(channel);
- note_on[channel] = 0;
-
- /* waste two bytes */
- read(fd, &tmp_byte, 1);
- read(fd, &tmp_byte, 1);
- break;
- case 0x90:
- /* get note */
- read(fd, &tmp_byte, 1);
- /* determine note */
-
- /* turn note on */
- channel = status & 0x0f;
- if (note_on[channel])
- Sb_FM_Key_Off(channel);
- note_on[channel] = 1;
- Sb_FM_Key_On(channel,note_table[tmp_byte % 12],(tmp_byte/12) & 7);
-
- /* waste a bytes */
- read(fd, &tmp_byte, 1);
- break;
- case 0xA0:
- printf("polyphonic key pressure: not handled\n");
- /* waste two bytes */
- read(fd, &tmp_byte, 1);
- read(fd, &tmp_byte, 1);
- break;
- case 0xB0:
- printf("control change: not handled\n");
- /* waste two bytes */
- read(fd, &tmp_byte, 1);
- read(fd, &tmp_byte, 1);
- break;
- case 0xC0:
- /* change the instrument on a channel */
- read(fd, &tmp_byte, 1);
- load_instrument(status&0x0F, tmp_byte & 0x0F);
- break;
- case 0xD0:
- printf("Channel Pressure: not handled\n");
- /* waste a byte */
- read(fd, &tmp_byte, 1);
- break;
- case 0xE0:
- printf("Pitch Wheel Change: not handled\n");
- /* waste two bytes */
- read(fd, &tmp_byte, 1);
- read(fd, &tmp_byte, 1);
- break;
- case 0xF0:
- printf("System Exclusive: not handled\n");
- /* waste two bytes */
- read(fd, &tmp_byte, 1);
- read(fd, &tmp_byte, 1);
- break;
- default:
- printf("internal program error\n");
- /* waste two bytes */
- read(fd, &tmp_byte, 1);
- read(fd, &tmp_byte, 1);
- break;
- }
-
-
- return(0);
- }
-
-
- /*
- * load an instrument from the instrument table into the SoundBlaster
- */
- int load_instrument(channel, instrument)
- {
- int rc;
-
- /* error check! */
- if ((channel <0) || (channel >= 9))
- return;
-
- /* abort instrument if being loaded */
- if (note_on[channel])
- Sb_FM_Key_Off(channel);
-
- /* set instrument characteristics */
- Sb_FM_Set_Voice(channel,instrument_table[instrument]);
- return(0);
- }
-